#include "droplist.hpp"

void DropList::CheckMouse(void* l){
    ((DropList*)l)->_on=-1;
    if(!((DropList*)l)->extend){
        return;
    }
    int x,y;
    SDL_GetMouseState(&x,&y);
    auto &r=((DropList*)l)->_area;
    if(x<r.x||x>r.x+r.w||y<r.y||y>r.y+r.h){
        ((DropList*)l)->_belong->RemoveTask(((DropList*)l)->_task);
        ((DropList*)l)->_task=NULL;
        return;
    }
    y-=r.y+((DropList*)l)->_h;
    if(y>=0){
        ((DropList*)l)->_on=((DropList*)l)->cur_item+y/((DropList*)l)->item_height;
    }
}

size_t DropList::selected(){return _select;}

DropList::DropList(Window* window,SDL_Rect& rect,initializer_list<string*> init
,int item_height,size_t max_item,Font* font,SDL_Color text_color,
SDL_Color background,SDL_Color on_color,SDL_Color line_color,
SDL_Color select_color,SDL_Color disable_color):Control(window){
    extend=false;
    this->select_color=select_color;
    _on=-1;
    _task=NULL;
    _t=window->renderer->CreateTexture(rect.w-5,rect.h);
    _h=rect.h;
    _area=rect;
    _i=window->renderer->CreateTexture(rect.w-5,item_height);
    this->disable_color=disable_color;
    this->text_color=text_color;
    this->background=background;
    this->line_color=line_color;
    this->on_color=on_color;
    cur_item=0;
    _select=-1;
    _items=new vector<string*>(init);
    this->item_height=item_height;
    this->max_item=max_item;
    this->font=font;
}
DropList::DropList(Window* window):Control(window){
    select_color=Color::Blue;
    _on=-1;
    _task=NULL;
    _t=window->renderer->CreateTexture(0,0);
    extend=false;
    disable_color=Color::Gray;
    background=Color::White;
    line_color=Color::Black;
    text_color=Color::Black;
    on_color=Color::SkyBlueGray;
    cur_item=0;
    _select=-1;
    _items=new vector<string*>();
    item_height=15;
    max_item=6;
    font=default_font;
    _i=window->renderer->CreateTexture(0,0);
}

void DropList::SetSize(int w,int h){
    _h=h,_area.w=w;
    if(!extend){
        _area.h=h;
    }
    SDL_DestroyTexture(_t);
    SDL_DestroyTexture(_i);
    _t=_belong->renderer->CreateTexture(w-5,h);
    _i=_belong->renderer->CreateTexture(w-5,item_height);
}
//最大展示数
void DropList::SetMaxItem(size_t n){
    max_item=n;
}

void DropList::Add(const string& str){
    _items->push_back(new string(str));
}
//越界抛出out_of_range 返回该移除的string，需要手动析构
string* DropList::RemoveItem(size_t index){
    if(index<_items->size()){
        _select=-1;
        _on=-1;
        auto temp=_items->operator[](index);
        _items->erase(_items->begin()+index);
        return temp;
    }
    throw out_of_range(to_string(index));
}
//越界抛出out_of_range
string* DropList::GetItem(size_t index){
    if(index<_items->size()){
        return _items->operator[](index);
    }
    throw out_of_range(to_string(index));
}

void DropList::_press(int x,int y,int clicks){}

void DropList::_draw(){
    auto r=_belong->renderer;
    if(!_enabled){
        r->SetColor(disable_color);
        r->FillRect(_area);
        r->SetColor(line_color);
        r->DrawRect(_area);
        return;
    }
    if(_select==-1){
        r->SetColor(background);
        r->FillRect(_area);
    }
    else{
        auto s=_items->operator[](_select);
        auto d=s->data();
        r->RenderHorizontalText(_t,background,font,d,d+s->length(),text_color);
        auto c=_area.h;
        _area.h=_h;
        r->DrawTexture(NULL,&_area,_t);
        _area.h=c;
    }
    r->SetColor(line_color);
    r->DrawRect(_area);
    auto x=_area.x,w=_area.w,y=_area.y,h=_h;
    auto vx=x+w-3,vy=y+(h>>1);
    r->SetColor(text_color);
    SDL_Point v1{vx,vy-3},v2{vx-3,vy+3};
    r->DrawLine(v1,v2);
    v1.x-=6;
    r->DrawLine(v1,v2);
    if(!extend){
        return;
    }
    SDL_Rect rect{x+5,y+h,w-5,item_height};
    auto i=_i;
    for(auto item=_items->begin()+cur_item,o=_items->begin()+_on,end=_items->end(),s=_items->begin()+_select,
    m=item+max_item;item!=end;item++){
        if(item==m){
            r->SetColor(line_color);
            r->DrawRect(_area);
            return;
        }
        auto _s=*item;
        auto _d=_s->data();
        if(item==o){
            r->RenderHorizontalText(i,on_color,font,_d,_d+_s->length(),text_color);
            r->DrawTexture(NULL,&rect,i);
            rect.y+=rect.h;
            continue;
        }
        if(item==s){
            r->RenderHorizontalText(i,select_color,font,_d,_d+_s->length(),text_color);
            r->DrawTexture(NULL,&rect,i);
            rect.y+=rect.h;
            continue;
        }
        r->RenderHorizontalText(i,background,font,_d,_d+_s->length(),text_color);
        r->DrawTexture(NULL,&rect,i);
        rect.y+=rect.h;
        continue;
    }
    r->SetColor(line_color);
    r->DrawRect(_area);
}

void DropList::_release(int x,int y,int clicks,unsigned char key){
    y-=_area.y+_h;
    if(y<=0){
        cur_item=0;
        extend=!extend;
        if(extend){
            _area.h=_h+item_height*min(max_item,_items->size());
        }
        else{
            _area.h=_h;
        }
        return;
    }
    _select=y/item_height+cur_item;
    OnSelect();
    extend=false;
    _area.h=_h;
}

void DropList::_mouse_wheel(SDL_MouseWheelEvent& e){
    if(_items->empty()){
        return;
    }
    auto y=e.y;
    if(y<0){
        //下
        y=-y;
        if(cur_item+y<_items->size()){
            cur_item+=y;
            return;
        }
        cur_item=_items->size()-1;
        return;
    }
    if(y>0){
        //上
        if(cur_item>=y){
            cur_item-=y;
            return;
        }
        cur_item=0;
    }
}

void DropList::_mouse_move(int x,int y){
    if(!_task){
        _task=_belong->AddTask(CheckMouse,this,1,false,true);
    }
}

DropList::~DropList(){
    if(_task){
        _belong->RemoveTask(_task);
    }
    for(auto item=_items->begin(),end=_items->end();item!=end;item++){
        delete *item;
    }
    delete _items;
    SDL_DestroyTexture(_t);
    SDL_DestroyTexture(_i);
}
void DropList::LoseFocus(){
    extend=false;
    _area.h=_h;
}